import Logger from "./logger";
import { SDKConfig } from "./types";

type RequestInterceptor = (input: RequestInfo, init: RequestInit) => Promise<[RequestInfo, RequestInit]> | [RequestInfo, RequestInit];
type ResponseInterceptor<T = any> = (response: T) => Promise<T> | T;

export class ApiClient {
  private baseUrl: string;
  private apiKey: string;
  protected logger: Logger;

  private requestInterceptor?: RequestInterceptor;
  private responseInterceptor?: ResponseInterceptor;

  constructor(options: SDKConfig) {
    this.baseUrl = options.baseURL.replace(/\/$/, '');
    this.apiKey = options.apiKey;
    this.logger = new Logger(options.debug ?? false, options.logLevel ?? "debug")
  }

  // 注册请求拦截器
  setRequestInterceptor(interceptor: RequestInterceptor) {
    this.requestInterceptor = interceptor;
  }

  // 注册响应拦截器
  setResponseInterceptor(interceptor: ResponseInterceptor) {
    this.responseInterceptor = interceptor;
  }

  private async request<T>(path: string, options: RequestInit = {}): Promise<T> {
    let url = `${this.baseUrl}${path}` as RequestInfo;
    
    const headers = { ...options.headers, ...(this.apiKey ? { "Ocr-Api-Key": `${this.apiKey}` } : {}) };
    if (!(options.body instanceof FormData)) {
      // @ts-ignore
      headers['Content-Type'] = headers['Content-Type'] || 'application/json';
    }
    let fetchOptions: RequestInit = {
      ...options,
      headers: headers
    };

    // 执行请求拦截器
    if (this.requestInterceptor) {
      [url, fetchOptions] = await this.requestInterceptor(url, fetchOptions);
    }

    const res = await fetch(url, fetchOptions);

    const text = await res.text();

    if (!res.ok) {
      if (this.responseInterceptor) {
        await this.responseInterceptor(Promise.reject(new Error(`HTTP ${res.status} - ${text}`)));
      }
      this.logger.error(`HTTP ${res.status} - ${text}`)
      throw new Error(`HTTP ${res.status} - ${text}`);
    }

    let data: T;

    try {
      data = JSON.parse(text);
    } catch {
      data = text as unknown as T;
    }

    // 执行响应拦截器
    if (this.responseInterceptor) {
      data = await this.responseInterceptor(data);
    }

    this.logger.debug(`HTTP ${res.status} ${options.method} ${url}`)
    return data;
  }

  async clientGet<T>(path: string, options: RequestInit = {}): Promise<T> {
    return this.request<T>(path, {
      ...options,
      method: 'GET'
    });
  }

  async clientPost<T>(path: string, body: any, options: RequestInit = {}): Promise<T> {
    return this.request<T>(path, {
      ...options,
      method: 'POST',
      body: JSON.stringify(body)
    });
  }

  async clientPut<T>(path: string, body: any, options: RequestInit = {}): Promise<T> {
    return this.request<T>(path, {
      ...options,
      method: 'PUT',
      body: JSON.stringify(body)
    });
  }

  async clientDelete<T>(path: string, options: RequestInit = {}): Promise<T> {
    return this.request<T>(path, {
      ...options,
      method: 'DELETE'
    });
  }

  async clientUpload<T>(path: string, file: File, prompt: string, options: RequestInit = {}): Promise<T> {
    const formData = new FormData();
    formData.append('file', file);
    formData.append('prompt', prompt);

    return this.request<T>(path, {
      ...options,
      method: 'POST',
      body: formData
    });
  }
}
